package edu.hawaii.duedates.lender;

import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
import org.xml.sax.SAXException;
import com.meterware.httpunit.HttpUnitOptions;
import com.meterware.httpunit.WebForm;
import com.meterware.httpunit.WebResponse;
import com.meterware.httpunit.WebTable;

/**
 * UH Manoa Library class. Contains all the necessary methods to log in and retrieve the borrowed
 * items from the library system.
 * 
 * @author Daniel Tian
 * @author Aric West
 */
public class UhManoaLibrary extends Lender {
  /**
   * Constructor. Assigns the number of fields this class expects, the full library name, and
   * instantiates the ArrayList object used to store the list of borrowed items.
   */
  public UhManoaLibrary() {
    this.lenderName = "University of Hawaii at Manoa";
    this.url = "http://uhmanoa.lib.hawaii.edu/cgi-bin/Pwebrecon.cgi?DB=local&PAGE=pbLogon";
    this.field1Name = "BC";
    this.field2Name = "LN";
    this.logonFormName = "logonpage";
    this.loginFailedText = "Sorry, Login unsuccessful.";
    this.loggedOn = false;
  }
  
  /**
   * Logs into the Hawaii State Public Library system using a library id and a
   * PIN. This code is modified from Philip Johnson's bootstrap code available
   * here:
   * 
   * http://groups.google.com/group/ics-software-engineering-fall-2008/
   * web/DueDateBootstrap-1.0.1010.zip
   * 
   * @throws LogInException If the login was unsuccessful.
   */
  public void logIn() throws LogInException {
    if (this.field1Value == null) {
      throw new LogInException("id field is empty");
    }
    if (this.field2Value == null) {
      throw new LogInException("last name field is empty");
    }
    
    try {
      // Disable exceptions thrown on Javascript errors, this is required for this library
      HttpUnitOptions.setExceptionsThrownOnScriptError(false);
      
      WebResponse response = this.conversation.getResponse(this.url);
      
      WebForm form = response.getFormWithName(this.logonFormName);
      form.setParameter(this.field1Name, this.field1Value);
      form.setParameter(this.field2Name, this.field2Value);
      form.submit();
      
      response = this.conversation.getCurrentPage();
      
      if (response.getText().contains(this.loginFailedText)) {
        throw new LogInException("wrong user name or password");
      }
      else {
        this.loggedOn = true;
      }
    }
    catch (IOException e) {
      throw new LogInException("could not open login web page", e);
    }
    catch (SAXException e) {
      throw new LogInException("an error occurred while parsing the login web page", e);
    }
    catch (NullPointerException e) {
      throw new LogInException("null pointer encountered, page URL or layout may have changed", e);
    }
  }
  
  /**
   * Logs the user into the system and gets a list of their borrowed items.
   * 
   * @throws ParseItemException Thrown if there was a problem parsing the borrowed items.
   * @throws LogInException If an error occurred that prevented login.
   */
  public void queryBorrowedItems() throws ParseItemException, LogInException {
    if (!this.loggedOn) {
      this.logIn();
    }
    
    try {
      WebResponse response = this.conversation.getCurrentPage();
      WebTable table;
      
      if (!response.getText().contains("You have no items checked out.")) {
        if (response.getText().contains("Renew?")) {
          table = response.getTableStartingWith("Renew?");
        }
        else {
          // required for the test accounts that don't have a Renew column
          table = response.getTableStartingWith("Item");
        }
        
        List<String> fieldList = new ArrayList<String>();
        BorrowedItem item;
  
        String itemName;
        String dueDate;
        
        for (int i = 1; i < table.getRowCount(); i++) {
          itemName = null;
          dueDate = null;
          
          if (response.getText().contains("Renew?")) {
            itemName = this.parseItemName(table.getCellAsText(i, 1));
            dueDate = table.getCellAsText(i, 3);
          }
          else {
            // the test accounts don't have a renew column
            itemName = this.parseItemName(table.getCellAsText(i, 0));
            dueDate = table.getCellAsText(i, 2);
          }
          
          try {
            item = new BorrowedItem(itemName, dueDate);
            this.itemList.add(item);
          }
          catch (BorrowedItemException e) {
            throw new ParseItemException("could not add item to the list:" + e.getMessage(), e);
          }
          
          fieldList.clear();
        }
      }
    }
    catch (IOException e) {
      throw new ParseItemException("could not open 'items out' web page", e);
    }
    catch (SAXException e) {
      throw new ParseItemException("an error occurred while parsing the 'items out' web page", e);
    }
    catch (NullPointerException e) {
      throw new ParseItemException(
        "null pointer encountered, page URL or layout may have changed", e);
    }
  }
  
  /**
   * Separates the title of the library book from it's author and returns the resulting string.
   * When querying the UH Manoa Library system, it displays the author followed by two spaces and
   * then the title of the library material. 
   * 
   * @param bookInfo The information string associated with a checked out.
   * @return The title of the checked out item.
   */
  private String parseItemName(String bookInfo) {
    // needs a comment describing what this regex does
    return bookInfo.replaceAll("(.*)  (.*)  (.*)", "$2");
  }

  /**
   * Checks that a compared object is this type they have the same name and item list.
   * Also should later check for equality of id and last name.
   * 
   * @param o object
   * @return boolean value
   */
  public boolean equals(Object o) {
    if (o == this) {
      return true;
    }
    if (!(o instanceof UhManoaLibrary)) {
      return false;
    }
    
    UhManoaLibrary query = (UhManoaLibrary)o;
    return query.lenderName.equals(this.lenderName) && query.itemList.equals(this.itemList);
  }

  /**
   * Calculates a hashcode for this object based on size of book list and expected parameters size.
   * Should use the id number later.
   * 
   * @return A hash value based on the due date of the item.
   */
  public int hashCode() {
    int hash = 7;
    hash = 31 * hash + this.lenderName.hashCode();
    hash = 31 * hash + this.itemList.hashCode();
    
    return hash;
  }
}
